#include<iostream>
#include<unistd.h>
#include<pthread.h>
#include<thread>
#include<cerrno>
#include<cstring>
#include<cstdio>

using namespace std;

// // 1. 线程谁先运行与调度器有关
// // 2. 线程一旦异常，都可能导致整个进程退出
// // 3. 线程的输入和返回值问题
// // 4. 线程异常退出的理解
// void* threadRoutine(void* args)
// {
//     int i = 0;
//     int* data = new int[10];
//     while(true)
//     {
//         cout << "新线程: " << (char*)args << " running ..." << pthread_self() << endl;
//         sleep(1);
//         data[i] = i;

//         // int a = 100;
//         // a /= 0;

//         //if ( i++ == 3) break;
//     }
//     // 线程退出
//     //exit(10); // 不要调用exit(), exit是用来终止进程的
//     pthread_exit((void*)13);

//     cout << " new thread quit ... " << endl;
//     //return nullptr;
//     //return (void*)10; // 返回值，返回给谁？  一般给mian thread，main如何获取到？ pthread_join
//     return (void*) data;
// }

// int main()
// {
//     // 因为我们目前用的不是Linux自带的创建进程的接口，我们用的是pthread库中的接口!
//     pthread_t tid; // 本质是一个地址
//     pthread_create(&tid, nullptr, threadRoutine, (void*)"thread 1");
//     printf("%lu, %p\n", tid, tid);

//     //// 3. 线程在创建并执行的时候，线程也是需要进行等待的，如果主线程如果不等待，即会引起类似于进程的僵尸问题，进而导致内存泄漏
//      int count = 0;
//      while(true)
//     {
//         cout << "main线程: " << " running ..." << endl;
//         sleep(1);
//         count++;
//         if (count  == 5) break;
//     }

//     // 取消线程，传入他的pthread_t 即可
//     // 1. 线程被取消，join的时候，退出码是-1
//     // PTHREAD_CANCELED;
//     pthread_cancel(tid);
//     cout << "pthread cancel: " << tid << endl;

//     // 线程等待
//     int* ret = nullptr; // Linux是64为，指针为8字节
//     pthread_join(tid, (void**)&ret); // 默认会阻塞等待新线程 第二个参数是用来接受返回参数的，返回参数是void*类型，要用二级指针来接受
    
//     //cout << " main thread wait done ...  main quit ...: new thread quit: " << (long long)ret << endl;
//     cout << " main thread wait done ...  main quit ...: new thread quit code: " << (long long)ret << endl;
//     sleep(5);
//     // for (int i = 0; i < 10; i++)
//     // {
//     //     cout << ret[i] << endl;
//     // }
//     return 0;
// }





// // 全局变量线程共享
// int g_vall = 0;

// // 全局变量线程私有   __thread : 修饰全局变量，带来的结果就是让每一个线程各自拥有一个全局变量-- 线程的局部存储
// __thread int g_val = 0;

// void* threadRoutine(void* args)
// {
//     //pthread_detach(pthread_self()); // 线程分离后主线程就不用管了。
//     // sleep(5);
//     // execl("/bin/ls", "ls", nullptr);  // 调用该接口后，整个进程都会被替换掉
//     while (true)
//     {
//         cout << (char*) args << " : " << g_val <<  " &: " << &g_val << endl;
//         g_val ++;
//         sleep(1);
//         break;
//     }
//     pthread_exit((void*)11);
// }

// int main()
// {
//     pthread_t tid;
//     pthread_create(&tid, nullptr, threadRoutine, (void*)"thread 1");


//     while (true)
//     {
//         cout << "main thread" << " : " << g_val <<  " &: " << &g_val << endl;
//         sleep(1);
//         break;
//     }

//     int n = pthread_join(tid, nullptr);

//     cout << "n: " << n << " errstring : " << strerror(n) << endl;
//     return 0;
// }





// void fun()
// {
//     while(true)
//     {
//         cout << "hello new thread" << endl;
//         sleep(1);
//     }
// }

// int main()
// {
//     thread t(fun);
//     thread t1(fun);
//     thread t2(fun);
//     thread t3(fun);
//     thread t4(fun);
    

//     while(true)
//     {
//         cout << "hello main thread" << endl;
//         sleep(1);
//     }

//     t.join();
//     return 0;
// }





// 如果多线程访问同一个全局变量，并对他进行数据计算，多线程会互相影响吗？
int tickets = 10000; // 在并发访问的时候，导致了我们数据不一致的问题！ 因为没有对数据进行保护。

void* getTickets(void* args)
{
    (void) args;
    while(true)
    {
        if (tickets > 0)
        {
            usleep(1000);
            printf("%p: %d\n", pthread_self(), tickets);
            tickets--;
        }
        else
        {
            break;
        }
    }

    return nullptr;
}

int main()
{
    pthread_t t1, t2, t3;
    // 多线程抢票
    pthread_create(&t1, nullptr, getTickets, nullptr);
    pthread_create(&t1, nullptr, getTickets, nullptr);
    pthread_create(&t1, nullptr, getTickets, nullptr);

    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);
    pthread_join(t3, nullptr);


    return 0;
}